package it.traveldream.beans;

import it.traveldream.dto.ExcursionDTO;
import it.traveldream.dto.HotelDTO;
import it.traveldream.dto.HotelDTO.HotelRoomType;
import it.traveldream.dto.LocationDTO;
import it.traveldream.dto.ReservationDTO;
import it.traveldream.dto.TransportMeanDTO;
import it.traveldream.dto.UserDTO;
import it.traveldream.exceptions.InvalidReservationException;
import it.traveldream.exceptions.LocationNotFoundException;
import it.traveldream.exceptions.ProductNotFoundException;
import it.traveldream.exceptions.ProductSoldOutException;
import it.traveldream.exceptions.ReservationNotFoundException;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.ejb.Local;

/**
 * 
 * @author Flavio Ferrara
 * <p>
 * BookingManagerInterface declares and describes available functions that the client can call
 * in order to book travel packages and handle reservations.
 * 
 * This interface will be implemented by one or more Enterprise Java Beans.
 */

@Local
public interface BookingManagerInterface {
	
	/**
	 * Returns a list of possible leaving date, included between two dates,
	 * on which a travel can start
	 * Maximum allowed interval between fromDate and toDate is 15 days 
	 * <p>
	 * It is required to the specified transport mean to have the 
	 * number of available spaces greater than travellers argument on
	 * the leaving date and the comingback date (leaving date + duration)
	 * @param mean The transport mean which must have available spaces
	 * @param fromDate Starting date to search availability
	 * @param toDate Final date to search availability
	 * @param duration Travel duration in days
	 * @param travellers Number of travellers
	 * @return List of dates
	 * @throws ProductNotFoundException
	 */
	public List<Date> getAvailableLeavingDates(TransportMeanDTO mean, Date fromDate, Date toDate, int duration, int travellers) throws ProductNotFoundException;
	
	/**
	 * Returns a list of possible hotels that have got enough free rooms 
	 * to host the travellers.
	 * <p>
	 * It is required to the returned hotels to have the 
	 * number of available rooms greater than rooms argument, for each type, on
	 * the whole period (since leavingDate until comingback date)
	 * 
	 * @param location Location in which hotel is placed
	 * @param fromDate Starting date to search availability
	 * @param toDate Final date to search availability
	 * @param rooms Number of rooms
	 * @return List of hotels
	 * @throws LocationNotFoundException
	 */
	public List<HotelDTO> getAvailableHotels(LocationDTO location, Date fromDate, Date toDate, Map<HotelRoomType, Integer> rooms) throws LocationNotFoundException;
	
	/**
	 * Return the number of available room, for each type,
	 * in a given hotel.
	 * @param hotel Hotel that contains the rooms
	 * @param fromDate Starting date to search availability
	 * @param toDate Final date to search availability
	 * @return Map: room type -> number of available room
	 * @throws ProductNotFoundException
	 */
	public Map<HotelRoomType, Integer> getAvailableHotelRooms(HotelDTO hotel, Date fromDate, Date toDate) throws ProductNotFoundException;
	
	/**
	 * Returns a list of possible excursions located in specified location,
	 * available to be booked during a travel between fromDate and toDate  
	 * @param location Location to be searched for
	 * @param fromDate Starting date to search availability
	 * @param toDate Final date to search availability
	 * @return List of excursions
	 * @throws LocationNotFoundException
	 */
	public List<ExcursionDTO> getAvailableExcursions(LocationDTO location, Date fromDate, Date toDate) throws LocationNotFoundException;
	
	/**
	 * Checks if transport mean and hotel are available to be booked.
	 * <p>
	 * It is required to return true that:
	 * <ul>
	 * <li>the specified transport mean has got 
	 * number of available spaces greater than travellers argument on
	 * the leaving date and the comingback date (leaving date + duration)
	 * <li> specified hotel to have the 
	 * number of available rooms greater than rooms argument, for each type, on
	 * the whole period (since leavingDate until comingback date)
	 * </ul>
	 * @param mean The transport mean
	 * @param hotel The hotel
	 * @param leavingDate Date when the travel starts
	 * @param endDate Date when the travel ends
	 * @param travellers Number of travellers
	 * @param rooms Number of rooms
	 * @return True if products are available, false otherwise
	 * @throws ProductNotFoundException
	 */
	public boolean checkAvailability(TransportMeanDTO mean, HotelDTO hotel, Date leavingDate, Date endDate, 
				int travellers, Map<HotelRoomType, Integer> rooms) throws ProductNotFoundException;
	
	/**
	 * Records in Persistence tier a Reservation and actually books the specified products
	 * for that customer, with given dates and number of travellers.
	 * <p>
	 * It requires that transport mean and hotel are available. Otherwise, an exception 
	 * will be thrown.
	 * In case withDiscount was true and the customer had a discount ticket available,
	 * it will be used
	 * @param reservation Reservation object that contains information about travel
	 * @param withDiscount Boolean value indicating whether to use discount ticket or not
	 * @return Representation of just created Reservation with generated ID
	 * @throws ProductNotFoundException
	 * @throws ProductSoldOutException
	 * @throws InvalidReservationException
	 */
	public ReservationDTO book(ReservationDTO reservation, boolean withDiscount) 
			throws ProductNotFoundException, ProductSoldOutException, InvalidReservationException;
	
	/**
	 * Return information about a specific reservation.
	 * The argument must contain a valid value for product ID field.
	 * @param reservation The reservation to be searched for.
	 * @return A representation of the reservation.
	 * @throws ReservationNotFoundException
	 */
	public ReservationDTO getReservation(ReservationDTO reservation) throws ReservationNotFoundException;
	
	/**
	 * Return information about a specific reservation.
	 * The argument must be a valid invitation link sent by
	 * some customer.
	 * @param invitationLink The invitation link received by email.
	 * @return A representation of the reservation.
	 * @throws ReservationNotFoundException
	 */
	public ReservationDTO getReservationByLink(String invitationLink) throws ReservationNotFoundException;
	
	/**
	 * Records in Persistence tier an invitation made by the customer
	 * to a given email address and returns an invitation link.
	 * <p>
	 * The implementation is not required to actually send the email.
	 * @param reservation Reservation which has been shared 
	 * @param customer Customer who made the reservation
	 * @param email Email address of invited person
	 * @return The brand new generated invitation link
	 * @throws ReservationNotFoundException
	 */
	public String sendInvitationLink(ReservationDTO reservation, UserDTO customer, String email) throws ReservationNotFoundException;
	
	/**
	 * Computes and returns the total price, given by following formula:
	 * (meanPrice * travellers) + (roomPrice * rooms * duration) + excursionsPrice
	 * 
	 * In case withDiscount was true and the customer had a discount ticket available,
	 * it will be used
	 * @param mean The transport mean
	 * @param hotel The hotel
	 * @param travellers Number of travellers
	 * @param duration Number of days
	 * @param hotelRooms Number of rooms
	 * @param excursions The list of excursions
	 * @param withDiscount Boolean value indicating whether to use discount ticket or not
	 * @return Total price
	 * @throws ProductNotFoundException
	 */
	public BigDecimal getTotalPrice(TransportMeanDTO mean, int travellers, int duration, HotelDTO hotel, Map<HotelRoomType, Integer> hotelRooms, 
			List<ExcursionDTO> excursions, boolean withDiscount) throws ProductNotFoundException;
}
